#include "StdAfx.h"
#include "GameState.h"
#include "Message.h"

#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

double positions[][2] = {
                         {0.1, 0.1}, 
                         {0.3, 0.12}, 
                         {0.6, 0.15},
                         {0.9, 0.25},
                         {0.2, 0.3},
                         {0.45, 0.5},
                         {0.8, 0.4},
                         {0.15, 0.9},
                         {0.55, 0.6},
                         {0.85, 0.65},
                         {0.5, 0.75}
                        };

PlanetSize planetsSize[] = {
                              smallPlanet,
                              mediumPlanet,
                              hugePlanet,
                              bigPlanet,
                              mediumPlanet,
                              smallestPlanet,
                              hugePlanet,
                              bigPlanet,
                              mediumPlanet,
                              mediumPlanet,
                              smallPlanet
                           };

const int maxCountOfPlanets = 11;
const int maxCountOfPlayers = 4;
const double defaultCountOfShips = 40;

GameState::GameState(unsigned int countOfPlanets, unsigned int countOfPlayers)
{
   generateBeginingState(countOfPlanets, countOfPlayers);
}

GameState::GameState()
{

}

GameState::~GameState(void)
{
}

void GameState::UpdatePlanets()
{
   BOOST_FOREACH(PlanetsMapPair planet, m_planets)
   {
      planet.second->IncreaseCountOfShips();
   }
}

void GameState::generateBeginingState(unsigned int countOfPlanets, unsigned int countOfPlayers)
{
   for (unsigned int i = 0; i < countOfPlanets; ++i)
   {
      PlanetID planetID(i);

      m_planets.insert(PlanetsMapPair(planetID, 
                       boost::make_shared<PlanetInternalImpl>(planetID, defaultCountOfShips, 
                       undefinedPlayerID, positions[i][0], positions[i][1],  
                       planetsSize[i])));
   }
   
   for (unsigned int i = 0; i < countOfPlayers; ++i)
   {
      PlayerID playerID(i);
      m_players.insert(PlayerMapPair(playerID, boost::make_shared<PlayerInternalImpl>(playerID,GameColors(i))));
      m_planets.at(PlanetID(i))->SetPlayerID(playerID);
   }
}

void GameState::SetShipCount( PlanetID planetID, double count )
{
   if (m_planets.find(planetID) != m_planets.end())
   {
      m_planets.at(planetID)->SetCountOfShips(count);
   }
   else
   {
      throw std::exception("GameState::SetShipCount planet does not exist");
   }
}

double GameState::GetShipCount( PlanetID planetID ) const
{
   if (m_planets.find(planetID) != m_planets.end())
   {
      return m_planets.at(planetID)->GetCountOfShips();
   }
   else
   {
      throw std::exception("GameState::GetShipCount planet does not exist");
   }
}

void GameState::AddPlanet( PlanetID planetID, PlanetInternalImplPtr planetPtr )
{
   if (m_planets.find(planetID) == m_planets.end())
   {
      m_planets.insert(PlanetsMapPair(planetID, planetPtr));
   }
   else
   {
      throw std::exception("GameState::AddPlanet trying to add planet that already exist");
   }
}

PlanetInternalImplPtr GameState::RemovePlanet( PlanetID planetID )
{
   if (m_planets.find(planetID) != m_planets.end())
   {
      PlanetInternalImplPtr planet = m_planets.find(planetID)->second;
      m_planets.erase(planetID);
      return planet;
   }
   else
   {
      throw std::exception("GameState::RemovePlanet trying to remove planet that does not exist");
   }
}

PlanetInternalImplPtr GameState::GetPlanet( PlanetID planetID )
{
   if (m_planets.find(planetID) != m_planets.end())
   {
      return m_planets.find(planetID)->second;
   }
   else
   {
      throw std::exception("GameState::GetPlanet trying to get planet that does not exist");
   }
}

void GameState::AddPlayer( PlayerID playerID, PlayerInternalImplPtr playerPtr )
{
   if (m_players.find(playerID) == m_players.end())
   {
      m_players.insert(PlayerMapPair(playerID, playerPtr));
   }
   else
   {
      throw std::exception("GameState::AddPlayer trying to add player that already exist");
   }
}

PlayerInternalImplPtr GameState::RemovePlayer( PlayerID playerID )
{
   if (m_players.find(playerID) != m_players.end())
   {
      PlayerInternalImplPtr player = m_players.find(playerID)->second;
      m_players.erase(playerID);
      return player;
   }
   else
   {
      throw std::exception("GameState::RemovePlayer trying to remove player that does not exist");
   }
}

PlayerInternalImplPtr GameState::GetPlayer( PlayerID playerID )
{
   if (m_players.find(playerID) != m_players.end())
   {
      return m_players.find(playerID)->second;
   }
   else
   {
      throw std::exception("GameState::GetPlayer trying to get player that does not exist");
   }
}